package cn.kevinkun.Box2D;

import org.jbox2d.dynamics.Body;
import org.jbox2d.dynamics.joints.DistanceJoint;
import org.jbox2d.dynamics.joints.DistanceJointDef;
import org.jbox2d.dynamics.joints.Joint;
import org.jbox2d.dynamics.joints.MouseJoint;
import org.jbox2d.dynamics.joints.MouseJointDef;
import org.jbox2d.dynamics.joints.RevoluteJoint;
import org.jbox2d.dynamics.joints.RevoluteJointDef;

import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.UsesAssets;
import com.google.appinventor.components.annotations.UsesLibraries;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;

@DesignerComponent(version = 1, //
		versionName = "", //
		category = ComponentCategory.EXTENSION, //
		description = "Manipulate joint in the boxWorld. You need to connect this with boxWorld by call SetBoxWorld as first step.", //
		iconName = "aiwebres/logo.jpg", //
		nonVisible = true, //
		helpUrl = "https://kevinkun.cn/box2d")
@UsesAssets(fileNames = "")
@UsesLibraries(libraries = "")
@SimpleObject(external = true)

public class BoxJoint extends AndroidNonvisibleComponent {
	BoxWorld boxWorld;

	public BoxJoint(ComponentContainer container) {
		super(container.$form());
	}

	@SimpleFunction
	public void SetBoxWorld(BoxWorld boxWorld) {
		this.boxWorld = boxWorld;
	}

	@SimpleFunction
	public Joint CreateMouseJoint(Body body, float x, float y) {
		assertWorld();
		MouseJointDef mjd = new MouseJointDef();
		mjd.bodyA = boxWorld.getWorld().getBodyList();
		mjd.bodyB = body;
		mjd.target.set(BoxUtil.pixelToVec2(x, y));
		MouseJoint mj = (MouseJoint) boxWorld.getWorld().createJoint(mjd);
		body.setAwake(true);
		return mj;
	}

	@SimpleFunction
	public void SetMouseJointDampingRatio(Joint joint, float ratio) {
		((MouseJoint) joint).setDampingRatio(ratio);
	}

	@SimpleFunction
	public void SetMouseJointFrequency(Joint joint, float hz) {
		((MouseJoint) joint).setFrequency(hz);
	}

	@SimpleFunction
	public void SetMouseJointMaxForce(Joint joint, float force) {
		((MouseJoint) joint).setMaxForce(force);
	}

	@SimpleFunction
	public void SetMouseJointTarget(Joint joint, float x, float y) {
		((MouseJoint) joint).setTarget(BoxUtil.pixelToVec2(x, y));
	}

	@SimpleFunction
	public Joint CreateRevoluteJoint(Body body1, Body body2, float x, float y) {
		assertWorld();
		RevoluteJointDef rjd = new RevoluteJointDef();
		rjd.initialize(body1, body2, BoxUtil.pixelToVec2(x, y));
		rjd.collideConnected = false;
		RevoluteJoint joint = (RevoluteJoint) boxWorld.getWorld().createJoint(rjd);
		return joint;
	}

	@SimpleFunction
	public void EnableRevoluteJointLimits(Joint joint, boolean enabled) {
		((RevoluteJoint) joint).enableLimit(enabled);
	}

	@SimpleFunction
	public void EnableRevoluteJointMotor(Joint joint, boolean enabled) {
		((RevoluteJoint) joint).enableMotor(enabled);
	}

	@SimpleFunction
	public void SetRevoluteJointLimits(Joint joint, float lowerAngle, float upperAngle) {
		((RevoluteJoint) joint).setLimits(BoxUtil.degreesToRadians(lowerAngle), BoxUtil.degreesToRadians(upperAngle));
	}

	@SimpleFunction
	public void SetRevoluteJointMotorSpeed(Joint joint, float speed) {
		((RevoluteJoint) joint).setMotorSpeed(speed);
	}

	@SimpleFunction
	public void SetRevoluteJointMaxMotorTorque(Joint joint, float torque) {
		((RevoluteJoint) joint).setMaxMotorTorque(torque);
	}

	@SimpleFunction
	public Joint CreateDistanceJoint(Body body1, Body body2, float anchor1X, float anchor1Y, float anchor2X,
			float anchor2Y) {
		assertWorld();
		DistanceJointDef djd = new DistanceJointDef();
		djd.initialize(body1, body2, BoxUtil.pixelToVec2(anchor1X, anchor1Y), BoxUtil.pixelToVec2(anchor2X, anchor2Y));
		return boxWorld.getWorld().createJoint(djd);
	}

	@SimpleFunction
	public Joint CreateDistanceJointWithBodyCenter(Body body1, Body body2) {
		assertWorld();
		DistanceJointDef djd = new DistanceJointDef();
		djd.initialize(body1, body2, body1.getPosition(), body2.getPosition());
		return boxWorld.getWorld().createJoint(djd);
	}

	@SimpleFunction
	public void SetDistanceJointDampingRatio(Joint joint, float ratio) {
		((DistanceJoint) joint).setDampingRatio(ratio);
	}

	@SimpleFunction
	public void SetDistanceJointFrequency(Joint joint, float hz) {
		((DistanceJoint) joint).setFrequency(hz);
	}

	@SimpleFunction
	public void SetDistanceJointaLength(Joint joint, float length) {
		((DistanceJoint) joint).setLength(BoxUtil.P2M(length));
	}

	@SimpleFunction
	public void DestryJoint(Joint joint) {
		assertWorld();
		boxWorld.getWorld().destroyJoint(joint);
		joint = null;
	}

	private void assertWorld() {
		if (boxWorld == null) {
			throw new RuntimeException("You need call SetBoxWorld before using Joint ");
		}
	}
}
